#include "KeySearchWidget.h"

#include <core/StyleMgr.h>

#include <QApplication>
#include <QBoxLayout>
#include <QDebug>
#include <QLabel>
#include <QLibrary>
#include <QMoveEvent>

#include "SImageButton.h"
#include "keysearch/DefaultItemDelegate.h"
#include "keysearch/KeySearchEdit.h"
#include "keysearch/KeySearchResultDlg.h"
#include "keysearch/TestSearchEngine.h"
#define KEY_CHANGE_TIME_OUT 100;  // 100ms

KeySearchWidget::KeySearchWidget(QWidget* parent, const QString& bgName,
                                 const QString& bgHoverName,
                                 const QString& borderName, int margin,
                                 bool showBorder, int itemHeight, int fontSize)
    : QFrame(parent),
      m_bgName(bgName),
      m_bgHoverName(bgHoverName),
      m_borderName(borderName),
      m_showBorder(showBorder) {
  QHBoxLayout* layout = new QHBoxLayout();
  layout->setContentsMargins(margin, 0, 0, 0);
  layout->setSpacing(0);
  m_label = new SImageButton(this, "widgets_search2");
  m_label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
  m_label->setFocusPolicy(Qt::FocusPolicy::ClickFocus);
  layout->addWidget(m_label);
  layout->setSpacing(margin == 0 ? 3 : margin);

  m_edit = new KeySearchEdit(this);
  m_label->setFocusProxy(m_edit);
  setFocusProxy(m_edit);
  layout->addWidget(m_edit);

  setLayout(layout);

  QString style =
      QString(
          "KeySearchWidget{border: 1px solid #%3; border-radius:2px; "
          "background:#%1}"
          "KeySearchWidget:hover{border: 1px solid #%4; border-radius:2px; "
          "background:#%2}")
          .arg(StyleMgr::instance().color(m_bgName).rgb(), 0, 16)
          .arg(StyleMgr::instance().color(m_bgHoverName).rgb(), 0, 16)
          .arg(StyleMgr::instance()
                   .color(m_showBorder ? m_borderName : m_bgName)
                   .rgb(),
               0, 16)
          .arg(StyleMgr::instance().color(m_borderName).rgb(), 0, 16);
  setStyleSheet(style);

  m_resultDlg = new KeySearchResultDlg(this, itemHeight);
  m_resultDlg->hide();

  connect(this, &KeySearchWidget::resultReached, m_resultDlg,
          &KeySearchResultDlg::onResultReached, Qt::QueuedConnection);
  connect(m_edit, &QLineEdit::textChanged, this,
          &KeySearchWidget::onSearchTextChanged);

  m_delegate = new DefaultItemDelegate(this, itemHeight, fontSize);
  setResultItemDelegate(m_delegate);
}

void KeySearchWidget::setSearchText(const QString& txt, bool blockSignal) {
  if (blockSignal) {
    m_blockSignal = true;
  }

  m_edit->setText(txt);
  m_edit->setCursorPosition(0);

  if (blockSignal) {
    m_blockSignal = false;
  }
}

void KeySearchWidget::appendSearchText(const QString& txt) {
  m_edit->setText(m_edit->text() + txt);
}

void KeySearchWidget::setPromptText(const QString& txt) {
  m_edit->setPlaceholderText(txt);
  m_promptText = txt;
}

void KeySearchWidget::setResultItemDelegate(
    QAbstractItemDelegate* itemDelegate) {
  m_resultDlg->setListItemDelegate(itemDelegate);
}

void KeySearchWidget::setResultDlgMaxHeight(int h) {
  m_resultDlg->setMaximumHeight(h);
}

void KeySearchWidget::setResultDlgMinWidth(int w) { m_widthResult = w; }

void KeySearchWidget::setColumnsWidth(int count, ...) {
  QVector<int> columnWidths;
  va_list vl;
  va_start(vl, count);

  for (int i = 0; i < count; ++i) {
    int width = va_arg(vl, int);
    columnWidths.push_back(width);
  }
  va_end(vl);
  m_delegate->setColumnWidth(columnWidths);
}

void KeySearchWidget::setSearchWhenEmpty(bool v) { m_searchWhenEmpty = v; }

void KeySearchWidget::setSearchEngine(IKeySearchEngine* se) {
  m_searchEngine = se;
  if (m_searchEngine)
    m_searchEngine->setResultCallback(std::bind(&KeySearchWidget::onResultReach,
                                                this, std::placeholders::_1,
                                                std::placeholders::_2));
}

void KeySearchWidget::setAutoSelect(bool bAutoSelect) {
  if (m_resultDlg) m_resultDlg->setAutoSelect(bAutoSelect);
}

void KeySearchWidget::setAutoKillFocus(bool bAutoKillFocus) {
  if (m_resultDlg) m_resultDlg->setAutoKillFocus(bAutoKillFocus);
}

void KeySearchWidget::setSearchEnable(bool enable) {
  if (m_label) {
    m_label->setEnabled(enable);
  }
  setEnabled(enable);
}

void KeySearchWidget::setEditFocusChangedClearText(bool clear) {
  m_editFocusChangedClearText = clear;
}

void KeySearchWidget::setEditFocus() { m_edit->setFocus(); }

void KeySearchWidget::foucsChanged(bool v) {
  if (v) {
    m_edit->setPlaceholderText(QString(""));
    QString style =
        QString(
            "KeySearchWidget {border: 1px solid #%2; border-radius:2px; "
            "background:#%1}")
            .arg(StyleMgr::instance().color("SearchBackHover").rgb(), 0, 16)
            .arg(StyleMgr::instance().color("Highlight").rgb(), 0, 16);
    setStyleSheet(style);
  } else {
    m_edit->setPlaceholderText(m_promptText);
    if (m_resultDlg->isHidden() && m_editFocusChangedClearText) m_edit->clear();

    QString style =
        QString(
            "KeySearchWidget {border: 1px solid #%3; border-radius:2px; "
            "background:#%1}"
            "KeySearchWidget:hover{border: 1px solid #%4; border-radius:2px; "
            "background:#%2}")
            .arg(StyleMgr::instance().color(m_bgName).rgb(), 0, 16)
            .arg(StyleMgr::instance().color(m_bgHoverName).rgb(), 0, 16)
            .arg(StyleMgr::instance()
                     .color(m_showBorder ? m_borderName : m_bgName)
                     .rgb(),
                 0, 16)
            .arg(StyleMgr::instance().color(m_borderName).rgb(), 0, 16);
    setStyleSheet(style);
  }

  emit searchFocusChanged(v);
}

void KeySearchWidget::hideResult() { m_resultDlg->hide(); }

void KeySearchWidget::clearEditFocus() { m_edit->clearFocus(); }

QString KeySearchWidget::getSearchKey() { return m_edit->text(); }

void KeySearchWidget::onResultReach(int serialNum, QJsonArray results) {
  if (serialNum == m_searchSerialNum) {
    resultReached(results);
  }
}

void KeySearchWidget::onSearchTextChanged(const QString& searchKey) {
  if (m_blockSignal) {
    return;
  }

  if (searchKey.isEmpty() && !m_searchWhenEmpty) {
    emit resultClear();

    m_resultDlg->hide();
    return;
  }

  ++m_searchSerialNum;  // TODO: max int
  // TODO: add time limit?
  if (m_searchEngine) {
    m_searchEngine->search(m_searchSerialNum, searchKey);
  }
}

void KeySearchWidget::resizeEvent(QResizeEvent*) {
  if (m_resultDlg) {
    if (m_widthResult > rect().width())
      m_resultDlg->setFixedWidth(m_widthResult);
    else
      m_resultDlg->setFixedWidth(rect().width());
  }
}